package com.jd.myaaaccount;

import java.io.IOException;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.common.HybridBinarizer;
import com.jd.myaaaccount.capture.DecodeFormatManager;
import com.jd.myaaaccount.capture.ViewfinderResultPointCallback;
import com.jd.myaaaccount.capture.ViewfinderView;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.widget.TextView;

public class ScanCodeActivity extends BaseActivity {
	private TextView tvCode;
	private SurfaceView svMain;
	private ViewfinderView vvMain;
	private SurfaceHolder holder;

	private Handler decodeHandler;
	Vibrator vibrator;

	private boolean hasSurface;
	private CameraManager cameraManager;
	private ViewfinderView viewfinderView;
	private MultiFormatReader multiFormatReader;
	private Collection<BarcodeFormat> decodeFormat;
	private Map<DecodeHintType, Object> decodeHints;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Window window = getWindow();
		window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		setContentView(R.layout.activity_scan_code);

		iniControl();

		multiFormatReader = new MultiFormatReader();
		multiFormatReader.setHints(initDecodeHints());

		decodeHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case R.id.decode:
					final byte[] data = (byte[]) msg.obj;
					final int w = msg.arg1;
					final int h = msg.arg2;
					new Thread(new Runnable() {
						@Override
						public void run() {
							// TODO Auto-generated method stub
							Result rawResult = null;
							PlanarYUVLuminanceSource source = cameraManager
									.buildLuminanceSource(data, w, h);
							if (source != null) {
								BinaryBitmap bbmp = new BinaryBitmap(
										new HybridBinarizer(source));
								try {
									rawResult = multiFormatReader.decode(bbmp);
								} catch (ReaderException e) {
									Log.e("decode", "reader ex");
								} catch (Exception e) {
									Log.e("decode", "error");
								} finally {
									multiFormatReader.reset();
								}
							}
							Message msgtemp = null;

							if (rawResult != null) {
								msgtemp = Message.obtain(decodeHandler,
										R.id.decode_succeeded, rawResult);
							} else {
								msgtemp = Message.obtain(decodeHandler,
										R.id.decode_failed);
							}
							msgtemp.sendToTarget();
						}
					}).start();
					break;
				case R.id.decode_succeeded:
					Result rawResult = (Result) msg.obj;
					Log.e("qrcode", rawResult.getText());
					hasSurface = false;
					cameraManager.stopPreview();
					// 震动
					vibrator.vibrate(200L);
					Intent intent = new Intent();
					intent.putExtra("code", rawResult.getText());
					setResult(1, intent);
					finish();
					break;
				case R.id.decode_failed:
					cameraManager.requestPreviewFrame(decodeHandler,
							R.id.decode);
					break;
				default:
					break;
				}
			}
		};

		holder = svMain.getHolder();
		holder.addCallback(new Callback() {

			@Override
			public void surfaceDestroyed(SurfaceHolder arg0) {
				hasSurface = false;
			}

			@Override
			public void surfaceCreated(SurfaceHolder arg0) {
				if (!hasSurface) {
					hasSurface = true;
					initCamera(holder);
				}
			}

			@Override
			public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
					int arg3) {

			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.scan_code, menu);
		return true;
	}

	@Override
	protected void onResume() {
		super.onResume();

		vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		cameraManager = new CameraManager(getApplication());
		vvMain.setCameraManager(cameraManager);
		if (hasSurface) {
			initCamera(holder);
		}
	}

	@Override
	protected void onPause() {
		super.onPause();
		cameraManager.closeDriver();
	}

	@Override
	public void onBackPressed() {
		Intent intent = new Intent();
		setResult(RESULT_OK, intent);
		super.onBackPressed();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {

		super.onActivityResult(requestCode, resultCode, data);
	}

	private void iniControl() {
		tvCode = (TextView) findViewById(R.id.tvCode);
		svMain = (SurfaceView) findViewById(R.id.svMain);
		vvMain = (ViewfinderView) findViewById(R.id.vvMain);
	}

	private void initCamera(SurfaceHolder holder) {
		if (cameraManager.isOpen())
			return;
		try {
			cameraManager.openDriver(holder);
			cameraManager.startPreview();
			cameraManager.requestPreviewFrame(decodeHandler, R.id.decode);
		} catch (IOException ie) {
			Log.e("OpenCamera", ie.getMessage());
		} catch (RuntimeException re) {
			Log.e("OpenCamera", re.getMessage());
		} catch (Exception e) {
			Log.e("OpenCamera", e.getMessage());
		}
	}

	public void drawViewfinder() {
		viewfinderView.drawViewfinder();
	}

	public Collection<BarcodeFormat> initDecodeFormat() {
		decodeFormat = EnumSet.noneOf(BarcodeFormat.class);
		decodeFormat.addAll(DecodeFormatManager.QR_CODE_FORMATS);
		// decodeFormat.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
		return decodeFormat;
	}

	public Map<DecodeHintType, Object> initDecodeHints() {
		decodeHints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
		decodeHints.put(DecodeHintType.POSSIBLE_FORMATS, initDecodeFormat());
		decodeHints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK,
				new ViewfinderResultPointCallback(vvMain));

		return decodeHints;
	}
}
